<?php
class Tagger2
{
/**
* Задачи выставляенные для класса Tagger
*  1. Автоматическое генерирование тегов для мемкешь объектов
* 		Исходя из данных полученных из объекта Query
*  2. Создание конкурентного тегирования
*  	    Одновременно не давать доступ к изменению удалению тега
*/

	/**
	* Определямем участвует ли в выборке один из ключей
	*  Если участвует то получаем его версию, 
	*  если версии еще нет создаем ее
	* @param mixed $object
	* @param Query $query
	*/
	public static function get( $object, Query $query ){
		$tags = Array();
		if(isset($object::$__tag_key)){
			$qValue = $query->getValue();
		# - Получаем список групп (Если он есть)
			foreach($object::$__tag_key as $group){
		# - Проверяем удоволивторяет ли запрос эту группу
		# 	А имеено участвуют ли поля этой группы в жтом запросе
				$group_val = Array();
				foreach($query->fields as $field){
					if( array_search($field["field"], $group) >= 0 ){
						$group_val[$field["field"]] = $qValue[substr($field["val"],1)];
					}
				}
		# Запрос удоволетворяет эту группу
				if( count($group_val) == count($group) ){
		# Создаем тег
		# Сортируем дабы все было в едином порядке
					ksort($group_val);
		# Генерируем имя тега и оборачиваем его md5
					$tag = md5("tag::".$object."::".implode($group_val,":"));
		# Проверяем хронится ли в мемкеше версия этого тега
					if( ($version = DB::getMCH()->get($tag)) === false) {
		# Если нет то запихиваем 1 версию.
			# Для того что бы версия тега не могла пересечься, то значение стартовой версии = текущее время в микросекундах 
						$version = microtime(true);
						@DB::getMCH()->set($tag, $version, 0, 3600);
					}				
					$tags[$tag] = $version ;
				}
			}
		}
		return $tags;
	}

	/**
	* Метод Вызывается в Worker 
	*  Он отвечает за то что бы получить текущии версии тегов из мемкеша и сравнить их
	* @param mixed $tags Массив тегов из полученного объекта
	*/
	public static function compare_tags( $tags ){
		# Если теги есть то пробегаем по ним циклом
		if( !empty( $tags ) ){
			foreach($tags as $tag => $version){
			# Пробуем получить версию из кеша
				if( ($vers = DB::getMCH()->get($tag)) !== false ){
			# Если версии не равны это провал 
					if($version != $vers){
						return false;
					}
				}else{
			# Если версия не найдена это провал, перекешируем запрос
					return false;	
				}
				
			}
		}
		return true;
	}

	/**
	* Вызывается во время манипуляций с объектом
	*  - Добавление
	*  - Сохранение
	*  - Удаления
	* 
	* @param string $obj - название объекта
	* @param Model $object - сам манипулируемый объект
	* @return Array() массив ключей
	*/
	public static function update($obj, Model $object){
		$tags = Array();
		if(isset($obj::$__tag_key)){
			foreach($object::$__tag_key as $group){
				$group_val = Array();
				foreach($group as $fil){
					$group_val[$fil] = $object->$fil;
				}
				if( count($group_val) == count($group) ){
				# Сортируем дабы все было в едином порядке
					ksort($group_val);
		# Генерируем имя тега и оборачиваем его md5
					$tag = md5("tag::".$obj."::".implode($group_val,":"));
		# Проверяем хронится ли в мемкеше версия этого тега
					$version = microtime(true);
					if( DB::getMCH()->get($tag) === false) {
		# Если нет то запихиваем 1 версию.
						@DB::getMCH()->set($tag, $version, 0, 3600);
					}else{
						DB::getMCH()->replace($tag, $version, 0 , 3600);
					}				
					$tags[$tag] = $version ;
				}
			}
		}
		return $tags;
	}

}

class Tagger
{
	public static $pref = "tag.v.2.0";
	/**
	* По результатам запроса должен выдать список тегов если запрос с использованием равенства 
	*  если версии еще нет создаем ее
	* @param string $object
	* @param Query $query
	*/
	public static function get( $object, Query $query ){
        return false;
	// Массив тегов для запроса
		$tagsList = Array(); // TagKey => TagValue
		
		
		// Формируем список тегов.
		foreach($query->tagValue as $tagValue){
			if( array_key_exists($tagValue["field"], $object::$__fields) ){
				if($object::$__fields[$tagValue["field"]] == "int"){
					//echo "{$tagValue["field"]} - {$tagValue["val"]}<br />";
					$tagsList[] =  md5( self::$pref . "::". $object . "::" . $tagValue["field"] . "::" . $tagValue["val"] );
				}else{
					@file_put_contents("/home/manfredi/data/ava.b3/cron/Tagger.txt","$object - {$tagValue["field"]} \n",FILE_APPEND);
				}
			}
		}
		$tags = array();
		$tags =  DB::getMCH()->get($tagsList);
		//print_r($tags);
		foreach($tagsList as $tag){
			if(!array_key_exists($tag, $tags)){
				$version = (int) str_replace(",","",microtime(true));
				$tags[$tag] = $version;
				@DB::getMCH()->set($tag, $version, 0, 3600);
			}
		}
		
		//var_dump($tags);
		return $tags;
	}
	/**
	* Вызывается во время манипуляций с объектом
	*  - Добавление
	*  - Сохранение
	*  - Удаления
	* 
	* @param string $obj - название объекта
	* @param Model $object - сам манипулируемый объект
	* @return Array() массив изменнеых тегов
	*/
	public static function update($obj, Model $object){
		$tags = array();
		$version = $version = (int) str_replace(",","",microtime(true));
	# Обвноление объекта
		if( count($object->__changes) > 0 && $object->__update ){
		#  - Проходим по массиву обновления и поднимаем версию тега старым элментам
		#  - И новым 
			foreach( $object->__changes as $field => $val){
				if($object::$__fields[$field] == "int"){
					$tag_arr = array();
				# - Тег для предыдущего значения
					$tag_arr[] = md5( self::$pref . "::". $obj . "::" . $field . "::" . $val );
				# - Тег для текущего значения 
					$tag_arr[] = md5( self::$pref . "::". $obj . "::" . $field . "::" . $object->$field );
					foreach($tag_arr as $tag){
					#  - Добавляем в массив измененных тегов
						$tags[$tag] = $version;
					#  - Проверяем наличие тега в кеше
						if( DB::getMCH()->get($tag) === false) {
						#  - Создаем новый
							@DB::getMCH()->set($tag, $version, 0, 3600 * 10);
						}else{
						#  - Заменяем предыдущий
							DB::getMCH()->replace($tag, $version, 0 , 3600 * 10);
						}
					}
				}
			}
	# Добавление \ удаление объекта 
	#  - При добавлении объекта нам надо сместить версию тега вверх
	#  - Тоже  самое в принципе и при удалении объекта надо сместить все критерии вверх. 	
		}else{
		#  - Пробегаемся по всем элементам объекта и поднимаем версию тега
		#  - Аналогичено как и при апдейте но только всем
			foreach($object::$__fields as $field => $type){
				if($type == "int"){
					//echo "$field  - {$object->$field}<br />";
					$tag = md5( self::$pref . "::". $obj . "::" . $field . "::" . $object->$field );
					$tags[$tag] = $version;
					if( DB::getMCH()->get($tag) === false) {
						@DB::getMCH()->set($tag, $version, 0, 3600 * 10);
					}else{
						DB::getMCH()->replace($tag, $version, 0 , 3600 * 10);
					}
				}
			}
		}
		return $tags;
		
	}
	
	/**
	* Метод Вызывается в Worker 
	*  Он отвечает за то что бы получить текущии версии тегов из мемкеша и сравнить их
	* @param mixed $tags Массив тегов из полученного объекта
	* @param mixed $tags2 Массив тегов для сравнивамеого запроса
	*/
	public static function compare_tags( $tags, $tags2 ){
		$tags = Utils::_objectToArray($tags);
	# Если массив тегов не пустой
		if( !empty( $tags2 ) ){
		# Сравниваем теги 
			if( !empty( $tags ) ){
				foreach($tags2 as $tag => $version){
					if( array_key_exists( $tag, $tags) ){
						if( $tags[$tag] !=  $version){
							return false;							
						}
					}else{
						//echo "Теги $tag не найден <br />";
						return false;
					}
				}
			}else{
				//echo "Теги не найдены <br />";
				return false;
			}
		}
	#  Метод отработал до конца и  не вернул false значит все ровно =) 
		return true;
		
	}
}
?>